#ifndef     __DECODE_H
#define     __DECODE_H

#include "./base.h"
#include "../utils/error.h"

namespace serialize {

template <typename T>
inline std::enable_if_t<std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t>, void>
decode_int(const uint8_t *buf, T& value) {
    value = buf[0];
}

template <typename T>
inline std::enable_if_t<std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t>, void>
decode_int(const uint8_t *buf, T& value) {
    value = (buf[0] << 8) + buf[1];
}

template <typename T>
inline std::enable_if_t<std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t>, void>
decode_int(const uint8_t *buf, T& value) {
    value = (buf[0] << 24) +
        (buf[1] << 16) +
        (buf[2] << 8) +
         buf[3];
}

template <typename T, typename... Ts>
Error decode(const uint8_t *buf, usize_t len, T&& value, Ts&&... ts) {
    using TYPE = std::decay_t<T>;
    
    if constexpr (std::is_integral_v<TYPE>) {
        constexpr usize_t size = sizeof(TYPE);
        if (len < size) {
            return ec::pub::PARSE_ERR;
        }
        decode_int<TYPE>(buf, value);

        if constexpr (sizeof...(Ts) != 0) {
            return decode(buf + size, len - size, std::forward<Ts>(ts)...);
        } else {
            return ec::pub::OK;
        }
    } else if constexpr (std::is_class_v<TYPE>) {
        if (len < TYPE::FLEX_LEN) {
            return ec::pub::PARSE_ERR;
        } 
        usize_t size = TYPE::content_len(buf) + TYPE::FLEX_LEN;

        if (len < size) {
            return ec::pub::PARSE_ERR;
        }
        value = TYPE::decode(buf);

        if constexpr (sizeof...(Ts) != 0) {
            return decode(buf + size, len - size, std::forward<Ts>(ts)...);
        } else {
            return ec::pub::OK;
        }
    }
}

}


#endif
